﻿using System;
using System.Collections.Generic;
using System.Text;
using Google.KML;
using System.Drawing;
using System.ComponentModel;
using KorTransLib;
using EARTHLib;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;

namespace GoogleEarthHelper
{
    /// <summary>
    /// Pafta Google Earth Helper.
    /// Kerem KAT
    /// </summary>
    public class PaftaGEHelper
    {
        private static Dictionary<int, int> dictÖlçekRange;

        static PaftaGEHelper()
        {
            dictÖlçekRange = new Dictionary<int, int>();
            dictÖlçekRange.Add(250000, 150000);
            dictÖlçekRange.Add(100000, 70000);
            dictÖlçekRange.Add(50000, 35000);
            dictÖlçekRange.Add(25000, 17500);
            dictÖlçekRange.Add(10000, 7000);
            dictÖlçekRange.Add(5000, 3500);
            dictÖlçekRange.Add(2500, 1750);
        }

        public static gePlacemark GetPaftaFeature(string name, Pafta p)
        {
            DecimalDegreeCoordinateConverter ddcc = new DecimalDegreeCoordinateConverter();
            DecimalDegreeCoordinate ddcGüneyBatı = (DecimalDegreeCoordinate)ddcc.ConvertFrom(p.GüneyBatıKöşesi);
            DecimalDegreeCoordinate ddcKuzeyDoğu = (DecimalDegreeCoordinate)ddcc.ConvertFrom(p.KuzeyDoğuKöşesi);

            gePlacemark pm = new gePlacemark();
            pm.Name = name;

            //Always complete the boundary by adding an end point that matches your beginning point
            List<geCoordinates> outerCoords = new List<geCoordinates>();
            outerCoords.Add(new geCoordinates(new geAngle90(ddcGüneyBatı.lat), new geAngle180(ddcGüneyBatı.lon)));
            outerCoords.Add(new geCoordinates(new geAngle90(ddcGüneyBatı.lat), new geAngle180(ddcKuzeyDoğu.lon)));
            outerCoords.Add(new geCoordinates(new geAngle90(ddcKuzeyDoğu.lat), new geAngle180(ddcKuzeyDoğu.lon)));
            outerCoords.Add(new geCoordinates(new geAngle90(ddcKuzeyDoğu.lat), new geAngle180(ddcGüneyBatı.lon)));
            outerCoords.Add(new geCoordinates(new geAngle90(ddcGüneyBatı.lat), new geAngle180(ddcGüneyBatı.lon)));

            geOuterBoundaryIs outer = new geOuterBoundaryIs(new geLinearRing(outerCoords));
            gePolygon poly = new gePolygon(outer);

            pm.StyleUrl = "#transBluePoly";
            poly.Extrude = true;
            poly.Tessellate = true;
            poly.AltitudeMode = geAltitudeModeEnum.clampToGround;

            pm.Geometry = poly;
            return pm;
        }

        public static geGroundOverlay GetPaftaAdıOverlay(string name, Pafta p)
        {
            DecimalDegreeCoordinateConverter ddcc = new DecimalDegreeCoordinateConverter();
            DecimalDegreeCoordinate ddcGüneyBatı = (DecimalDegreeCoordinate)ddcc.ConvertFrom(p.GüneyBatıKöşesi);
            DecimalDegreeCoordinate ddcKuzeyDoğu = (DecimalDegreeCoordinate)ddcc.ConvertFrom(p.KuzeyDoğuKöşesi);

            DecimalDegreeCoordinate fark = (DecimalDegreeCoordinate)(ddcKuzeyDoğu - ddcGüneyBatı);
            DecimalDegreeCoordinate merkez = (DecimalDegreeCoordinate)ddcc.ConvertFrom(p.Merkez());

            fark = (DecimalDegreeCoordinate)(fark / 16);
            fark.lon *= 4;

            ddcGüneyBatı = (DecimalDegreeCoordinate)(merkez - fark);
            ddcKuzeyDoğu = (DecimalDegreeCoordinate)(merkez + fark);

            geGroundOverlay.geLatLonBox latLonBox =
                new geGroundOverlay.geLatLonBox(
                    new geAngle90(ddcKuzeyDoğu.lat),
                    new geAngle90(ddcGüneyBatı.lat),
                    new geAngle180(ddcKuzeyDoğu.lon),
                    new geAngle180(ddcGüneyBatı.lon));

            geGroundOverlay go = new geGroundOverlay(latLonBox);
            string pngFilename = getPNGfile(name);
            geIcon gi = new geIcon(pngFilename);
            go.Icon = gi;
            go.AltitudeMode = geAltitudeModeEnum.clampToGround;
            //go.Altitude = 5000;
            return go;
        }

        public static Bitmap getPNG(string PaftaAdı)
        {
            Bitmap bmp = new Bitmap(333, 45);
            using (Font pngFont = new Font(FontFamily.GenericMonospace, 16, FontStyle.Bold))
            {
                using (Pen p = new Pen(Color.Blue, 2))
                {
                    using (Graphics g = Graphics.FromImage(bmp))
                    {
                        g.Clear(Color.White);
                        SizeF sz = g.MeasureString(PaftaAdı, pngFont);
                        float x = (bmp.Width - sz.Width) / 2;
                        float y = (bmp.Height - sz.Height) / 2;
                        g.DrawString(PaftaAdı, pngFont, Brushes.Black, x, y);
                        g.DrawRectangle(p, new Rectangle(1, 1, 331, 43));
                    }
                }
            }
            return bmp;
        }

        public static string getPNGfile(string PaftaAdı)
        {
            Bitmap bmp = getPNG(PaftaAdı);
            string filename = System.IO.Path.GetTempFileName() + ".png";
            bmp.Save(filename, System.Drawing.Imaging.ImageFormat.Png);
            return filename;
        }

        public static void GEFocusPafta(IApplicationGE ige, Pafta p)
        {
            int range = dictÖlçekRange[p.ÖlçekSayısı];
            DecimalDegreeCoordinate dd =
                (DecimalDegreeCoordinate)
                TypeDescriptor.GetConverter(typeof(DecimalDegreeCoordinate)).ConvertFrom(p.Merkez());
            ige.SetCameraParams(dd.lat, dd.lon, 0, EARTHLib.AltitudeModeGE.RelativeToGroundAltitudeGE, range, 0, 0, 1);
        }

        public static IApplicationGE GEBaşlat()
        {
            IApplicationGE ige;
            ige = new EARTHLib.ApplicationGEClass();

            while (ige.IsInitialized() != 1)
            {
                System.Threading.Thread.Sleep(300);
            }
            return ige;
        }

        public static void GEFocusTürkiye(IApplicationGE ige)
        {
            ige.SetCameraParams(39, 35, 1500000, EARTHLib.AltitudeModeGE.RelativeToGroundAltitudeGE, 0, 0, 0, 2);
        }

        public static void GEShowPafta(IApplicationGE ige, Pafta p)
        {
            EARTHLib.FeatureGE fge = ige.GetFeatureByName(p.PaftaAdı);
            if (fge != null)
                fge.Visibility = 0;

            geDocument doc = new geDocument();
            doc.Name = p.PaftaAdı;

            geStyle transBluePoly = new geStyle("transBluePoly");
            transBluePoly.LineStyle = new geLineStyle();
            transBluePoly.LineStyle.Width = 1.5f;
            geColor col = new geColor();
            col.SysColor = Color.FromArgb(0x7d, 0, 0, 0xFF);
            transBluePoly.PolyStyle = new gePolyStyle();
            transBluePoly.PolyStyle.Color = col;
            doc.StyleSelectors.Add(transBluePoly); ;

            geStyle pointStyle = new geStyle("namePoint");
            geIconStyle np = new geIconStyle();
            np.Scale = 0;
            pointStyle.IconStyle = np;
            doc.StyleSelectors.Add(pointStyle);
            //
            gePlacemark pmNokta = new gePlacemark();

            DecimalDegreeCoordinate dd = (DecimalDegreeCoordinate)TypeDescriptor.GetConverter(typeof(DecimalDegreeCoordinate)).ConvertFrom(p.Merkez());
            geCoordinates coords = new geCoordinates(new geAngle90(dd.lat), new geAngle180(dd.lon));
            gePoint pnt = new gePoint(coords);
            pmNokta.Geometry = new gePoint(coords);
            pmNokta.Name = p.PaftaAdı;
            pmNokta.StyleUrl = "#namePoint";
            //

            gePlacemark pm = GetPaftaFeature(p.PaftaAdı, p);
            doc.Features.Add(pm);
            doc.Features.Add(pmNokta);
            //doc.Features.Add(GetPaftaAdıOverlay(p.PaftaAdı, p));

            geKML kml = new geKML(doc);
            string strKML = Encoding.GetEncoding("ISO-8859-9").GetString(kml.ToKML());
            ige.LoadKmlData(ref strKML);
        }

        public static void GETüm250000Paftalar(IApplicationGE ige)
        {
            string featureName = "250.000'lik paftalar";
            EARTHLib.FeatureGE fge = ige.GetFeatureByName(featureName);
            if (fge != null)
                fge.Visibility = 0;

            geDocument doc = new geDocument();
            doc.Name = featureName;

            geStyle transBluePoly = new geStyle("transBluePoly");
            transBluePoly.LineStyle = new geLineStyle();
            transBluePoly.LineStyle.Width = 1.5f;
            geColor col = new geColor();
            col.SysColor = Color.FromArgb(0x7d, 0, 0, 0xFF);
            transBluePoly.PolyStyle = new gePolyStyle();
            transBluePoly.PolyStyle.Color = col;
            doc.StyleSelectors.Add(transBluePoly);


            geStyle pointStyle = new geStyle("namePoint");
            geIconStyle np = new geIconStyle();
            np.Scale = 0;
            pointStyle.IconStyle = np;
            doc.StyleSelectors.Add(pointStyle);

            gePlacemark pm;
            Pafta p;
            gePlacemark pmNokta;

            foreach (string s in Pafta.paftaİsimleri())
            {
                p = Pafta.PaftaGetir(s);
                pm = PaftaGEHelper.GetPaftaFeature(s, p);
                doc.Features.Add(pm);
                pmNokta = new gePlacemark();

                DecimalDegreeCoordinate dd = (DecimalDegreeCoordinate)TypeDescriptor.GetConverter(typeof(DecimalDegreeCoordinate)).ConvertFrom(p.Merkez());
                geCoordinates coords = new geCoordinates(new geAngle90(dd.lat), new geAngle180(dd.lon));
                gePoint pnt = new gePoint(coords);
                pmNokta.Geometry = new gePoint(coords);
                pmNokta.Name = p.PaftaAdı;
                pmNokta.StyleUrl = "#namePoint";

                doc.Features.Add(pmNokta);
                //doc.Features.Add(PaftaGEHelper.GetPaftaAdıOverlay(s, p));
            }

            geKML kml = new geKML(doc);
            string strKML = Encoding.GetEncoding("ISO-8859-9").GetString(kml.ToKML());
            ige.LoadKmlData(ref strKML);

            GEFocusTürkiye(ige);
        }

        private static gePolygon GetPolygon(Coordinate[] coords)
        {
            if (coords != null && coords.Length < 2)
            {
                throw new ArgumentException("Poligon en az 3 adet koordinattan oluşur.", "coords");
            }

            List<geCoordinates> outerCoords = new List<geCoordinates>();
            DecimalDegreeCoordinate dd;
            foreach (Coordinate c in coords)
            {
                dd = (DecimalDegreeCoordinate)TypeDescriptor.GetConverter(typeof(DecimalDegreeCoordinate)).ConvertFrom(c);
                outerCoords.Add(new geCoordinates(new geAngle90(dd.lat), new geAngle180(dd.lon)));
            }
            //Always complete the boundary by adding an end point that matches your beginning point
            dd = (DecimalDegreeCoordinate)TypeDescriptor.GetConverter(typeof(DecimalDegreeCoordinate)).ConvertFrom(coords[0]);
            outerCoords.Add(new geCoordinates(new geAngle90(dd.lat), new geAngle180(dd.lon)));

            geOuterBoundaryIs outer = new geOuterBoundaryIs(new geLinearRing(outerCoords));
            gePolygon poly = new gePolygon(outer);

            poly.Extrude = true;
            poly.Tessellate = true;
            poly.AltitudeMode = geAltitudeModeEnum.clampToGround;

            return poly;
        }

        public static void GEShowPolygon(IApplicationGE ige, string name, Coordinate[] coords)
        {
            geDocument doc = new geDocument();
            doc.Name = name;


            geStyle paftaPoly = new geStyle("paftaPoly");
            paftaPoly.LineStyle = new geLineStyle();
            paftaPoly.LineStyle.Width = 1.5f;
            geColor col = new geColor();
            col.SysColor = Color.FromArgb(0x7d, 0x7f, 0, 0);
            paftaPoly.PolyStyle = new gePolyStyle();
            paftaPoly.PolyStyle.Color = col;
            doc.StyleSelectors.Add(paftaPoly);

            gePolygon poly = GetPolygon(coords);

            gePlacemark pm = new gePlacemark();
            pm.Name = name;
            pm.Geometry = poly;
            pm.StyleUrl = "#paftaPoly";
            doc.Features.Add(pm);

            geKML kml = new geKML(doc);
            string strKML = Encoding.GetEncoding("ISO-8859-9").GetString(kml.ToKML());
            ige.LoadKmlData(ref strKML);

            //GEFocusTürkiye(ige);
        }

        private static string GetCrosshairURL()
        {
            string filename = System.IO.Path.GetTempFileName() + ".png";
            ResourceGEH.crosshairs.Save(filename);
            return filename;
        }

        private static geFeature GetNokta(string name, string snippet, string description, Coordinate coord)
        {
            geStyle stil = new geStyle("noktaIcon");
            geIconStyle icon = new geIconStyle();
            icon.Icon = new geIcon(GetCrosshairURL());
            geVec2 gv2 = new geVec2();
            gv2.x = 10;
            gv2.y = 10;
            icon.HotSpot = gv2;
            stil.IconStyle = icon;
            
            gePlacemark pm = new gePlacemark();
            DecimalDegreeCoordinate dd = (DecimalDegreeCoordinate)TypeDescriptor.GetConverter(typeof(DecimalDegreeCoordinate)).ConvertFrom(coord);
            geCoordinates coords = new geCoordinates(new geAngle90(dd.lat), new geAngle180(dd.lon));
            //Create a point with these new coordinates 
            gePoint point = new gePoint(coords);
            //Assign the point to the Geometry property of the placemark.
            pm.Geometry = point;
            //Now lets add some other properties to our placemark 
            pm.Name = name;
            pm.Snippet = snippet;
            if (description.Length == 0)
                description = GetKoordinatlar(coord);
            else
                description = description + "<br />" + GetKoordinatlar(coord);
            pm.StyleSelectors.Add(stil);
            pm.StyleUrl = "#noktaIcon";
            pm.Description = description;
            //Finally, add the placemark to the document
            return pm;
        }
     
        public static void GEShowNokta(IApplicationGE ige, string root, string name, string snippet, string description, Coordinate coord)
        {
            geDocument doc = new geDocument();
            doc.Name = root;
            doc.Features.Add(GetNokta(name, snippet, description, coord));
            //Now that we have our document, lets create our KML
            geKML kml = new geKML(doc);
            string strKML = Encoding.GetEncoding("ISO-8859-9").GetString(kml.ToKML());
            ige.LoadKmlData(ref strKML);
        }

        public static void GEFocusNokta(IApplicationGE ige, Coordinate coord)
        {
            int range = 35000;
            DecimalDegreeCoordinate dd =
                (DecimalDegreeCoordinate)
                TypeDescriptor.GetConverter(typeof(DecimalDegreeCoordinate)).ConvertFrom(coord);
            ige.SetCameraParams(dd.lat, dd.lon, 0, EARTHLib.AltitudeModeGE.RelativeToGroundAltitudeGE, range, 0, 0, 1);
        }

        public static void GEShowRuhsat(IApplicationGE ige, string name, Ruhsat ruh)
        {
            geDocument doc = new geDocument();
            doc.Name = name;
            doc.Snippet = name;

            geStyle paftaPoly = new geStyle("paftaPoly");
            paftaPoly.LineStyle = new geLineStyle();
            paftaPoly.LineStyle.Width = 1.5f;
            geColor col = new geColor();
            col.SysColor = Color.FromArgb(0x7d, 0x7f, 0, 0);
            paftaPoly.PolyStyle = new gePolyStyle();
            paftaPoly.PolyStyle.Color = col;
            doc.StyleSelectors.Add(paftaPoly);

            string html = RuhsatXSLT(ruh);
            doc.Description = html;
            List<geFeature> points;
            List<gePolygon> polygons = RuhsatPolygons(ruh, out points);
            doc.Features.AddRange(points);

            int i = 1;
            foreach (gePolygon poly in polygons)
            {
                gePlacemark pm = new gePlacemark();
                pm.Name = string.Format("{0}poligon{1}", name, i++);
                pm.Snippet = pm.Name;
                pm.Geometry = poly;
                pm.StyleUrl = "#paftaPoly";
                doc.Features.Add(pm);
            }

            geKML kml = new geKML(doc);
            string strKML = Encoding.GetEncoding("ISO-8859-9").GetString(kml.ToKML());
            ige.LoadKmlData(ref strKML);


        }

        private static List<gePolygon> RuhsatPolygons(Ruhsat ruh, out List<geFeature> polygonPoints)
        {
            string utmZone = "35S";
            foreach (string strp in ruh.Paftalar)
            {
                Pafta p = Pafta.PaftaGetir(strp);
                UTMCoordinate utm = (UTMCoordinate)TypeDescriptor.GetConverter(typeof(UTMCoordinate)).ConvertFrom(p.Merkez());
                utmZone = utm.Zone;// herhangi bir zoneu al.
                //GEShowPafta(ige, p);
            }

            int paftaAdedi = 0;
            List<int> paftaNo = new List<int>();
            foreach (RuhsatKoordinat rk in ruh.Koordinatlar)
            {
                if (!paftaNo.Contains(rk.PaftaNo))
                    paftaNo.Add(rk.PaftaNo);
            }
            paftaAdedi = paftaNo.Count;

            List<List<UTMCoordinate>> koord = new List<List<UTMCoordinate>>();
            for (int i = 0; i < paftaAdedi; i++)
                koord.Add(new List<UTMCoordinate>());

            List<geFeature> points = new List<geFeature>();
            foreach (RuhsatKoordinat rk in ruh.Koordinatlar)
            {
                UTMCoordinate utm = new UTMCoordinate(utmZone, rk.Sağa, rk.Yukarı);
                koord[rk.PaftaNo - 1].Add(utm);
                points.Add(
                    GetNokta(
                    rk.SıraNo.ToString(),
                    string.Format("Pafta No: {0} Sıra No: {1}", rk.PaftaNo, rk.SıraNo),
                    string.Format("Pafta No: {0} Sıra No: {1}", rk.PaftaNo, rk.SıraNo),
                    utm));
            }

            List<gePolygon> ret = new List<gePolygon>();
            foreach (List<UTMCoordinate> polykoord in koord)
            {
                ret.Add(GetPolygon(polykoord.ToArray()));
            }
            polygonPoints = points;
            return ret;
        }

        private static string RuhsatXSLT(Ruhsat ruh)
        {
            try
            {
                XPathDocument xpdXsl = new XPathDocument(new System.IO.StringReader(ResourceGEH.ruhsat));
                XslCompiledTransform xct = new XslCompiledTransform();
                xct.Load(xpdXsl);

                XPathDocument xpdXml = new XPathDocument(new XmlTextReader(new System.IO.StringReader(ruh.GetXMLString())));

                StringBuilder sbSonuc = new StringBuilder();
                System.IO.StringWriter swSonuc = new System.IO.StringWriter(sbSonuc);

                xct.Transform(xpdXml, new XsltArgumentList(), swSonuc);
                return sbSonuc.ToString();
            }
            catch (System.Xml.Xsl.XsltCompileException ex)
            {
                throw ex;
            }
            catch (System.Xml.Xsl.XsltException ex)
            {
                throw ex;
            }
        }

        private static string GetKoordinatlar(Coordinate coord)
        {
            StringBuilder sbRet = new StringBuilder();
            sbRet.Append("<strong>DD :</strong> ");
            sbRet.AppendLine(((DecimalDegreeCoordinate)TypeDescriptor.GetConverter(typeof(DecimalDegreeCoordinate)).ConvertFrom(coord)).ToString());

            sbRet.Append("<br /><strong>DMS :</strong> ");
            sbRet.AppendLine(((DegreeMinuteSecondCoordinate)TypeDescriptor.GetConverter(typeof(DegreeMinuteSecondCoordinate)).ConvertFrom(coord)).ToString());

            sbRet.Append("<br /><strong>UTM :</strong> ");
            sbRet.AppendLine(((UTMCoordinate)TypeDescriptor.GetConverter(typeof(UTMCoordinate)).ConvertFrom(coord)).ToString());
            sbRet.Append("<br />");
            return sbRet.ToString();
        }

     //   private static void KesitAl(Coordinate cFrom, Coordinate cTo, out KeyValuePair<Coordinate, 
    }
}
